/*
 * Copyright � 2008 Nokia Corporation.
 */


#include <fbs.h>
#include <eikenv.h>

#include <sudoku_svg.mbg>

#include "SudokuBtnControl.h"
#include "SudokuGridControl.h"
#include "SudokuStatisticControl.h"
#include "SudokuAppView.h"
#include "SudokuGameLogic.h"
#include "GraphicEngine.h"
#include "SudokuAppUi.h"

CSudokuGridControl::CSudokuGridControl (CSudokuContainerControl& aParent, CFbsBitGc*& aBgc)
: iBgc(aBgc), iParent(aParent)
    {
    // No implementation required
    }

CSudokuGridControl::~CSudokuGridControl ( )
    {
    }

CSudokuGridControl* CSudokuGridControl::NewLC (CSudokuContainerControl& aParent, const TRect& aRect, CFbsBitGc*& aBgc)
    {
    CSudokuGridControl* self = new (ELeave)CSudokuGridControl(aParent, aBgc);
    CleanupStack::PushL (self );
    self->ConstructL (aRect);
    return self;
    }

CSudokuGridControl* CSudokuGridControl::NewL (CSudokuContainerControl& aParent, const TRect& aRect, CFbsBitGc*& aBgc)
    {
    CSudokuGridControl* self=CSudokuGridControl::NewLC (aParent, aRect, aBgc);
    CleanupStack::Pop ( ); // self;
    return self;
    }

void CSudokuGridControl::ConstructL (const TRect& /*aRect*/)
    {
    SetContainerWindowL(iParent);

    iRed = KRgbRed;
    iRed.SetAlpha(90);
    
    iGameLogic = iParent.GameLogic();
    iGraphicEngine = static_cast<CSudokuAppUi*>(iEikonEnv->EikAppUi())->GraphicEngine();
    iActiveItemPoint = TPoint(-1,-1);
    }

void CSudokuGridControl::Draw( const TRect& /*aRect*/ ) const
    {
    // Remember to draw into backbuffer iBgc
    iBgc->SetPenColor(KRgbBlack);
    DrawGrid();
    iBgc->SetPenColor(KRgbBlack);
    DrawGridLines();
    }


TBool CSudokuGridControl::IsActiveItem(TGridItem& aItem) const
    {
    TBool ret = EFalse;

    TRect rect = aItem.iRect;
    if (rect.iTl.iY < iActiveItemPoint.iY &&
        rect.iBr.iY > iActiveItemPoint.iY)
        {
        ret = ETrue;
        }
    else if (rect.iTl.iX < iActiveItemPoint.iX &&
            rect.iBr.iX > iActiveItemPoint.iX)
        {
        ret = ETrue;
        }
    
    return ret;
    }

void CSudokuGridControl::DrawGridLines() const
    {
    iBgc->SetPenSize(TSize(4,4));
    
    TPoint tl = Rect().iTl;
    TPoint br = Rect().iBr;

    iBgc->DrawLine(TPoint(tl.iX + iGridAreaWidth,tl.iY+4),TPoint(tl.iX + iGridAreaWidth,br.iY-6));
    iBgc->DrawLine(TPoint(tl.iX + iGridAreaWidth*2-1,tl.iY+4),TPoint(tl.iX + iGridAreaWidth*2-1,br.iY-6));

    iBgc->DrawLine(TPoint(tl.iX+4,tl.iY + iGridAreaHeight),TPoint(br.iX-6,tl.iY + iGridAreaHeight));
    iBgc->DrawLine(TPoint(tl.iX+4,tl.iY + iGridAreaHeight*2-1),TPoint(br.iX-6,tl.iY + iGridAreaHeight*2-1));
    
    
    iBgc->SetPenSize(TSize(1,1));
    }

void CSudokuGridControl::ResetCellAnim()
    {
    iInvalidCellAnim = iInvalidCellAnimMax;
    }

void CSudokuGridControl::UpdateCellAnim()
    {
    iInvalidCellAnim = iInvalidCellAnim - iInvalidCellAnimMax / 10;
    
    if (iInvalidCellAnim < 0)
        {
        iInvalidCellAnim = iInvalidCellAnimMax;
        }
    }

void CSudokuGridControl::DrawGrid() const
    {
    TBuf<2>number;
    
    iParent.UseFont(iParent.GridFont());

    TInt txtWidth = iParent.GridFont()->TextWidthInPixels(_L("8"));
    TInt txtHeight = iParent.GridFont()->HeightInPixels();
    
    if (iGameLogic)
        {
        RArray<TGridItem>* items =  iGameLogic->GridItems();
        if (items)
            {
            for (TInt i=0 ; i<items->Count() ; i++)
                {
                TGridItem item = (*items)[i];
                
                TRect itemRect = TRect(TPoint(0,0),item.iRect.Size());
                if (IsActiveItem(item))
                    {
                    // Active grid item
                    iBgc->BitBltMasked(item.iRect.iTl,
                                            iGraphicEngine->BitmapSVG(EMbmSudoku_svgLightgriditem),
                                            itemRect,
                                            iGraphicEngine->BitmapSVG(EMbmSudoku_svgLightgriditem_mask),
                                            EFalse);
                    }
                else
                    {
                    switch (item.iArea)
                        {
                        case 0:
                        case 2:
                        case 4:
                        case 6:
                        case 8:
                            {
                            // Grid item
                            iBgc->BitBltMasked(item.iRect.iTl,
                                               iGraphicEngine->BitmapSVG(EMbmSudoku_svgDarkgriditem),
                                               itemRect,
                                               iGraphicEngine->BitmapSVG(EMbmSudoku_svgDarkgriditem_mask),
                                               EFalse);
                            break;
                            }
                        case 1:
                        case 3:
                        case 5:
                        case 7:
                            {
                            // Grid item
                            iBgc->BitBltMasked(item.iRect.iTl,
                                                iGraphicEngine->BitmapSVG(EMbmSudoku_svgBrowngriditem),
                                                itemRect,
                                                iGraphicEngine->BitmapSVG(EMbmSudoku_svgBrowngriditem_mask),
                                                EFalse);
                            break;
                            }
                        default:
                            {
                            break;
                            }
                        };
                    }
                
                number.Zero();
                number.AppendNum(item.iValue);
                
                if (item.iValue!=0)
                    {
                    TPoint textPoint = item.iRect.iTl;
                    textPoint.iY += txtHeight;
                    textPoint.iX += (item.iRect.Width() - txtWidth) / 2;
                    if (item.iShowConflict)
                        {
                        iBgc->SetPenColor(iRed);
                        iBgc->SetBrushStyle(CGraphicsContext::ESolidBrush);
                        iBgc->SetBrushColor(iRed);
                        TPoint p = item.iRect.iTl;
                        p.iX += iInvalidCellAnim/2;
                        p.iY += iInvalidCellAnim/2;
                        iBgc->DrawRect(TRect(p,TSize(item.iRect.Width() - iInvalidCellAnim,item.iRect.Height() - iInvalidCellAnim)));
                        iBgc->SetBrushStyle(CGraphicsContext::ENullBrush);

                        iBgc->SetPenColor(KRgbRed);
                        }
                    else if (item.iLocked)
                        {
                        iBgc->SetPenColor(KRgbBlack);
                        }
                    else
                        {
                        iBgc->SetPenColor(KRgbWhite);
                        }
                    iBgc->DrawText(number,textPoint);
                    }
                }
            }
        }
    }



void CSudokuGridControl::SizeChanged()
    {
    // Update grid item size
    iGameLogic->SetBoardItemRects(Rect());
    
    iActiveItemPoint = Rect().Center();

    // 3x3 area size
    iGridAreaWidth = Rect().Width() / SUDOKU_AREA_SIZE;
    iGridAreaHeight = Rect().Height() / SUDOKU_AREA_SIZE;
    
    // Update grid item bitmaps size
    TGridItem item = (*iGameLogic->GridItems())[0];
    iInvalidCellAnimMax = item.iRect.Width();
    iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgDarkgriditem,item.iRect.Size());
    iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgLightgriditem,item.iRect.Size());
    iGraphicEngine->SetSVGBitmapSize(EMbmSudoku_svgBrowngriditem,item.iRect.Size());
    }

TKeyResponse CSudokuGridControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType)
    {
    TKeyResponse ret = EKeyWasNotConsumed;
    
    if (aType == EEventKeyDown)
        {
        TInt gridMoveLength = Rect().Width() / SUDOKU_GRID_SIZE;
        switch (aKeyEvent.iScanCode)
            {
            case EStdKeyUpArrow:
                {
                if (iActiveItemPoint.iY > Rect().iTl.iY + gridMoveLength)
                    {
                    iActiveItemPoint.iY -= gridMoveLength;
                    ret = EKeyWasConsumed;
                    }
                break;
                }
            case EStdKeyDownArrow:
                {
                if (iActiveItemPoint.iY + gridMoveLength < Rect().iBr.iY)
                    {
                    iActiveItemPoint.iY += gridMoveLength;
                    ret = EKeyWasConsumed;
                    }
                break;
                }
            case EStdKeyLeftArrow:
                {
                if (iActiveItemPoint.iX > Rect().iTl.iX + gridMoveLength)
                    {
                    iActiveItemPoint.iX -= gridMoveLength;
                    ret = EKeyWasConsumed;
                    }
                break;
                }
            case EStdKeyRightArrow:
                {
                if (iActiveItemPoint.iX + gridMoveLength < Rect().iBr.iX)
                    {
                    iActiveItemPoint.iX += gridMoveLength;
                    ret = EKeyWasConsumed;
                    }
                break;
                }
            case EStdKeyDevice3:
                {
                TGridItem* item = iGameLogic->GetActiveItem(iActiveItemPoint);
                if (item && !item->iLocked)
                    {
                    // Grid item selected, show number selection control
                    iParent.BtnControl()->MakeVisible(ETrue);
                    }
                ret = EKeyWasConsumed;
                break;
                }
            default:
                {
                break;
                }
            };
        }
    return ret;
    }

void CSudokuGridControl::HandlePointerEventL(const TPointerEvent& aPointerEvent)
    {
    // If menu is invisible open button control
    if (iParent.MenuControl()->IsVisible())
        {
        return;
        }
    
    if (Rect().Contains(aPointerEvent.iPosition))
        {
        if (aPointerEvent.iType == TPointerEvent::EButton1Down)
            {
            iActiveItemPoint = aPointerEvent.iPosition;
            }
        else if (aPointerEvent.iType == TPointerEvent::EDrag)
            {
            iActiveItemPoint = aPointerEvent.iPosition;
            }    
        else if (aPointerEvent.iType == TPointerEvent::EButton1Up)
            {
            iActiveItemPoint = aPointerEvent.iPosition;

            TGridItem* item = iGameLogic->GetActiveItem(aPointerEvent.iPosition);
            if (item && !item->iLocked)
                {
                // Grid item selected, show number selection control
                iParent.BtnControl()->MakeVisible(ETrue);
                }
            }
        }
    else
        {
        iActiveItemPoint = Rect().Center();
        }
    }

void CSudokuGridControl::NumberBtnPressed(TInt aValue)
    {
    TGridItem* item = iGameLogic->GetActiveItem(iActiveItemPoint);
    if (item && !item->iLocked)
        {
        iGameLogic->CleanConflicts();
        iGameLogic->SetValue(iActiveItemPoint, aValue);
        iParent.StatisticControl()->UpdateData();
        }
    }

